package com.fs.base.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.transaction.Transactional;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

import org.apache.log4j.Logger;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSON;
import com.fs.base.param.SysConstant;
import com.fs.base.pojo.Menu;
import com.fs.base.pojo.MenuMotion;
import com.fs.base.pojo.Org;
import com.fs.base.pojo.Role;
import com.fs.base.pojo.RoleMenuAccess;
import com.fs.base.pojo.RoleRight;
import com.fs.base.pojo.User;
import com.fs.base.pojo.UserRole;
import com.fs.base.repository.MenuMotionRepository;
import com.fs.base.repository.MenuRepository;
import com.fs.base.repository.OrgRepository;
import com.fs.base.repository.RoleMenuAccessRepository;
import com.fs.base.repository.RoleRightRepository;
import com.fs.base.repository.UserRepository;
import com.fs.base.repository.UserRoleRepository;
import com.fs.base.utils.CollectionTools;
import com.fs.base.utils.Md5Utils;
import com.fs.base.vo.LoginUser;

@Service("roleService")
@AllArgsConstructor
public class RoleService {
	private static final Logger log = Logger.getLogger(RoleService.class);
	@Setter @Getter  private UserRoleRepository userRoleRepository;
	@Setter @Getter  private UserRepository userRepository;
	@Setter @Getter private MenuRepository menuRepository;
	@Setter @Getter private MenuMotionRepository menuMotionRepository;
	@Setter @Getter private RoleRightRepository roleRightRepository;
	@Setter @Getter private OrgRepository orgRepository;
	@Setter @Getter private RoleMenuAccessRepository roleMenuAccessRepository;
	
	@Transactional
	public void configRoleRight(String roleId,List<RoleRight> list,String accessJson){
		roleRightRepository.deleteByRoleId(roleId);
		roleRightRepository.save(list);
		
		roleMenuAccessRepository.deleteByRoleId(roleId);
		List<RoleMenuAccess> accessList = JSON.parseArray(accessJson, RoleMenuAccess.class);
		if(!CollectionUtils.isEmpty(accessList)){
			roleMenuAccessRepository.save(accessList);
		}
	}
	
	@Transactional
	public void configUserRole(String userId,List<UserRole> list){
		userRoleRepository.deleteByUserId(userId);
		userRoleRepository.save(list);
	}
	
	public LoginUser login(User user){
		LoginUser loginVo = null;
		String account = user.getAccount();
		User u = null;
		try {
			u = userRepository.findByAccountAndPwd(account, Md5Utils.md5(user.getPwd()));
		} catch (Exception e) {
			log.error(e.getMessage());
			e.printStackTrace();
		}
		if(u!=null){
			if("1".equals(String.valueOf(u.getStatus()))){
				loginVo = LoginUser.builder().user(user).loginStatus(false)
						.loginResult("该账号已被禁用，请联系客服").loginTime(new Date()).build();
				return loginVo;
			}
			Boolean sysAdm = u.isSysAdm();
			loginVo = LoginUser.builder().user(u).loginStatus(true)
					.loginResult("登录成功!").loginTime(new Date()).build();
			List<Role> roles = new ArrayList<Role>();
			List<Menu> menus = new ArrayList<Menu>();
			List<MenuMotion> motions = new ArrayList<MenuMotion>();
			//排序
			Sort _sort = new Sort(Sort.Direction.ASC, "menuOrder");  
			if(sysAdm){
				menus = menuRepository.findAll(_sort);
				Set<Object> menuIds = CollectionTools.convertListFeild2Set(menus, "id");
				List<MenuMotion> _motions = menuMotionRepository.findByMenuIdInOrderByMotionOrderAsc(menuIds);
				motions.addAll(_motions);
				//loginVo.setDataRight(9);
			}else{
				//Long time1 = System.currentTimeMillis();
				List<Role> _roles = userRoleRepository.findRoleByUserId(u.getId());
				roles.addAll(_roles);
				
				//System.out.println("加载角色数据耗时："+ (System.currentTimeMillis()-time1) );
				/*
				 * 根据角色id查找数据权限并设置到对象
				 */
				//Long time2 = System.currentTimeMillis();
				Set<String> roleIdSet = new HashSet<>();
				for(Role r:_roles){
					roleIdSet.add(r.getId());
				}
				List<RoleMenuAccess> accesses = roleMenuAccessRepository.findByRoleIdIn(roleIdSet);
				Map<String, Integer> menuAccessMap = new HashMap<>();
				String accessK = null; 
				Integer accessV;
				for(RoleMenuAccess a: accesses){
					accessK = a.getMenuId(); 
					//System.out.println("accessK:"+ a);
					if(menuAccessMap.containsKey(accessK)){
						accessV = menuAccessMap.get(accessK);
						if(a.getAccess()>accessV){
							menuAccessMap.put(accessK, a.getAccess());
						}
					}else{
						menuAccessMap.put(accessK, a.getAccess());
					}
				}
				loginVo.setMenuAccessMap(menuAccessMap);
				//System.out.println("加载角色数据权限耗时："+ (System.currentTimeMillis()-time2) );
				/*
				 * 当前用户的所属部门集合
				 * @return
				 */
				/*
				 * 所有菜单动作权限
				 */
				//Long time3 = System.currentTimeMillis();
				List<MenuMotion>  _motions = roleRightRepository.findUserRolesMenuMotion(roleIdSet);
				motions.addAll(_motions);
				//System.out.println("加载菜单动作权限耗时："+ (System.currentTimeMillis()-time3) );
				/*
				 * 设置部门数据权限
				 */
				//List<String> departments =  getDepartments(u);
				//loginVo.setDepartments(departments);
				
				/*
				 * 设置个人数据权限类型
				 */
				//loginVo.setDataRight(setDataRight(roles));
				
				/*
				 * 所有菜单权限
				 */
				//Long time4 = System.currentTimeMillis();
				Set<Object> _menuId = CollectionTools.convertListFeild2Set(_motions, "menuId");
				List<Menu> _menus = menuRepository.findByIdInOrderByMenuOrderAsc(_menuId);
				menus.addAll(_menus);
				
				List<Menu> parents = findParentMenus(menus);
				menus.addAll(parents);
				//System.out.println("加载菜单权限耗时："+ (System.currentTimeMillis()-time4) );
			}
			
			/*
			 * 角色权限
			 */
			loginVo.setRoles(roles);
			/*
			 * 菜单权限
			 */
			loginVo.setMenus(menus);
			
			/*
			 * 动作权限
			 */
			//Long time5 = System.currentTimeMillis();
			Map<String, List<MenuMotion>> menuMotionMap = new HashMap<String, List<MenuMotion>>();
			String menuKey = null;
			for(MenuMotion mm: motions){
				List<MenuMotion> tempList = null;
				menuKey = mm.getMenuId();
				if(menuMotionMap.containsKey(menuKey)){
					tempList = menuMotionMap.get(menuKey);
				}else{
					tempList = new ArrayList<MenuMotion>();
				}
				tempList.add(mm);
				menuMotionMap.put(menuKey, tempList);
			}
			loginVo.setMotions(menuMotionMap);
			//System.out.println("菜单及动作组合耗时："+ (System.currentTimeMillis()-time5) );
			
			//刷新数据
			loadUserIdNameMap();
			
			loadOrgNoNameMap();
			
		}else{
			loginVo = LoginUser.builder().user(user).loginStatus(false)
					.loginResult("用户名或是密码错误!").loginTime(new Date()).build();
		}
		return loginVo;
	}
	
	/**
	 * 递归获取所有父菜单
	 * @param list
	 * @return
	 */
	private List<Menu> findParentMenus(List<Menu> list){
		List<Menu> parentList = new ArrayList<Menu>();
		
		Set<Object> parentIds = CollectionTools.convertListFeild2Set(list,"parentId");
		List<Menu> tempList  = null;
		if(!CollectionUtils.isEmpty(parentIds)){
			tempList = menuRepository.findByIdInOrderByMenuOrderAsc(parentIds);
		}
		if(tempList!=null && tempList.size()>0){
			parentList.addAll(tempList);
			findParentMenus(tempList);
		}
		return parentList;
	}
	
	/**
	 * 加载用户id-name
	 */
	public void loadUserIdNameMap(){
		new Thread(new Runnable() {
			public void run() {
				List<User> userList = userRepository.findAll(); 
				for(User u: userList){
					SysConstant.USERS_ID_NAME_MAP.put(u.getId(), u.getNickName());
				}
			}
		}).start();;
	}
	
	/**
	 * 加载组织no-name集合
	 */
	public void loadOrgNoNameMap(){
		new Thread(new Runnable() {
			public void run() {
				List<Org> orgList = orgRepository.findAll(); 
				for(Org o: orgList){
					SysConstant.ORG_NO_NAME_MAP.put(o.getOrgNo(), o.getOrgName());
				}
			}
		}).start();;
	}
}
